package com.mrdeer.iot;

import com.mrdeer.iot.constant.FrameConst;
import com.mrdeer.iot.handler.*;
import com.mrdeer.iot.utils.CRCUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * Netty服务器
 */
@Slf4j
@Component
public class NettyServer {

    /**
     * DeviceId:Channel
     * 用于存放设备的Netty Context Channel
     */
    // dest:Device
    public static final Map<String, Channel> deviceChannelMap = new ConcurrentHashMap<>(16);

    public static String status = "";

    private int port = 7777;

    @Resource
    private CommandHandler commandHandler;

    @Resource
    private ChannelManagerHandler channelManagerHandler;

    @Resource
    private ExceptionHandler exceptionHandler;

    @Resource
    private MQDeviceEventHandler mqDeviceEventHandler;

    @Resource
    private ProcessorHandler processorHandler;

    @Resource
    private HeartBeatHandler heartBeatHandler;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;

    @SneakyThrows
    public void start() {
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //TODO:先硬编码，待得到确认数据后该为配置的
                            pipeline.addLast(new IdleStateHandler(FrameConst.maxIdleTime, FrameConst.maxIdleTime, FrameConst.maxIdleTime, TimeUnit.SECONDS));
                            pipeline.addLast("logging", new LoggingHandler(LogLevel.INFO));
                            //添加自定义编解码器
                            pipeline.addLast(new ProtocolEncoderHandler());
                            pipeline.addLast(new ProtocolDecoderHandler());
                            //处理网络IO
                            pipeline.addLast(new WriteTimeoutHandler(30), heartBeatHandler);
                            pipeline.addLast(new WriteTimeoutHandler(30), channelManagerHandler);
                            pipeline.addLast(new WriteTimeoutHandler(30), processorHandler);
                            pipeline.addLast(new WriteTimeoutHandler(30), commandHandler);
                            pipeline.addLast(new WriteTimeoutHandler(30), mqDeviceEventHandler);
                            pipeline.addLast(new WriteTimeoutHandler(30), exceptionHandler);
                        }
                    });
            ChannelFuture future = bootstrap.bind().sync();
            log.info("Netty服务启动成功,监听端口:[port:" + port + "]" + ",CRC:" + CRCUtils.getCRC(FrameConst.crcs));

            future.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("Netty服务启动失败:" + e.getMessage());
        } finally {
            workerGroup.shutdownGracefully().sync();
            bossGroup.shutdownGracefully().sync();
        }
    }
}
